﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xrm.Sdk.Workflow;
using System.Activities;
using Microsoft.Xrm.Sdk;
using Microsoft.Crm.Sdk.Messages;
using Microsoft.Crm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using System.Xml.Serialization;
using System.IO;
using System.Runtime.Serialization;
using System.Xml;
using System.Text.RegularExpressions;

/**
 * Copyright 2011 by Alberto Gemin
 * agemin@hotmail.com
 * Version 1.7.0.1
 * 13 Dec 2011
 **/
namespace Gemina.CRM2011.WF.LdgManager
{
/*    [AgCodeActivity(ActivityNameRetrieveUserViews, AgViewsUtils.GroupName)]
    public class AgRetrieveUserViews : AgCodeActivityBase
    {

        #region Constants

        private const string ActivityNameRetrieveUserViews = "Retrieve User Views";
        private const string Param1InputUserQueryNameRegex = "Personal View Name Pattern (Regex)";
        private const string Param2InputUserQueryOwner = "Personal View Owner";
        private const string Param3InputUserViewReturnedTypeRegex = "Personal View Returned Entity Pattern (Regex)";
        private const string Param4InputUserQueryTypeRegex = "Personal View Query Type Pattern (Regex)";
        private const string Param5InputIncludeTemplatedFilters = "Include Templated Filters (N,V,I)";
        private const string Param1OutputViewCount = "Count of Views";
        private const string Param2OutputViewDefinitions = "View Definitions";
        private const string MsgInvalidRegex = "Invalid regular expression for {0}: \"{1}\" - Error: {2}";
        private const string MsgNull = "{0} cannot be null.";
        private const string MsgInvalidNVI = "{0} can only contain a combination of N, V or I characters. Invalid input: {1}.";

        #endregion

        #region Properties

        public EntityReference ValidatedUserQueryOwner { get; set; }
        public Regex ValidatedEntityLogicalNameRegex { get; set; }
        public Regex ValidatedUserQueryNameRegex { get; set; }
        public List<int> ValidatedQueryTypes { get; set; }
        public bool IncludeNotTemplated { get; set; }
        public bool IncludeInvalidTemplated { get; set; }
        public bool IncludeValidTemplated { get; set; }

        #endregion

        #region Workflow Input Parameters

        /// <summary>
        /// Input parameter
        /// </summary>
        [Input(Param1InputUserQueryNameRegex)]
        public InArgument<String> InputUserQueryNameRegex { get; set; }

        /// <summary>
        /// Input parameter
        /// </summary>
        [Input(Param2InputUserQueryOwner)]
        [ReferenceTarget(AgViewsUtils.EntityNameSystemUser)]
        [RequiredArgument]
        public InArgument<EntityReference> InputUserQueryOwner { get; set; }

        /// <summary>
        /// Input parameter
        /// </summary>
        [Input(Param3InputUserViewReturnedTypeRegex)]
        public InArgument<String> InputEntityLogicalNameRegex { get; set; }

        /// <summary>
        /// Input parameter
        /// </summary>
        [Input(Param4InputUserQueryTypeRegex)]
        public InArgument<String> InputQueryTypeRegex { get; set; }

        /// <summary>
        /// Input parameter
        /// </summary>
        [Input(Param5InputIncludeTemplatedFilters)]
        [Default("NVI")]
        public InArgument<String> InputIncludeTemplatedFilters { get; set; }

        #endregion

        #region Workflow Output Parameters

        /// <summary>
        /// Output parameter
        /// </summary>
        [Output(Param1OutputViewCount)]
        public OutArgument<int> OutputViewCount { get; set; }

        /// <summary>
        /// Output parameter
        /// </summary>
        [Output(Param2OutputViewDefinitions)]
        public OutArgument<String> OutputViewDefinitions { get; set; }

        #endregion

        #region CodeActivity

        override protected bool ExecuteBody(CodeActivityContext executionContext)
        {
            this.CheckArguments(executionContext);

            this.RetrieveUserQueries(executionContext);

            return true;
        }

        #endregion

        #region Local Methods

        private void CheckArguments(CodeActivityContext executionContext)
        {
            string queryTypePattern = this.InputQueryTypeRegex.Get(executionContext);
            this.ValidatedUserQueryOwner = this.InputUserQueryOwner.Get(executionContext);
            string returnedTypeRegex = this.InputEntityLogicalNameRegex.Get(executionContext);
            string nameRegex = this.InputUserQueryNameRegex.Get(executionContext);
            string includeTemplatedFilters = this.InputIncludeTemplatedFilters.Get(executionContext);

            if (this.ValidatedUserQueryOwner == null)
            {
                throw new AgErrorMessage(string.Format(MsgNull, Param2InputUserQueryOwner));
            }

            Regex queryTypeRegex = null;
            if (string.IsNullOrEmpty(queryTypePattern))
            {
                queryTypeRegex = new Regex(".*", RegexOptions.IgnoreCase);
            }
            else
            {
                try
                {
                    queryTypeRegex = new Regex(queryTypePattern, RegexOptions.IgnoreCase);
                }
                catch (ArgumentException ex)
                {
                    throw new AgErrorMessage(string.Format(MsgInvalidRegex, Param4InputUserQueryTypeRegex, queryTypePattern, ex.Message));
                }
            }
            this.ValidatedQueryTypes = AgViewsUtils.GetUserQueryTypes(queryTypeRegex);

            if (string.IsNullOrEmpty(returnedTypeRegex))
            {
                this.ValidatedEntityLogicalNameRegex = new Regex(".*", RegexOptions.IgnoreCase);
            }
            else
            {
                try
                {
                    this.ValidatedEntityLogicalNameRegex = new Regex(returnedTypeRegex, RegexOptions.IgnoreCase);
                }
                catch (ArgumentException ex)
                {
                    throw new AgErrorMessage(string.Format(MsgInvalidRegex, Param3InputUserViewReturnedTypeRegex, returnedTypeRegex, ex.Message));
                }
            }

            if (string.IsNullOrEmpty(nameRegex))
            {
                this.ValidatedUserQueryNameRegex = new Regex(".*", RegexOptions.IgnoreCase);
            }
            else
            {
                try
                {
                    this.ValidatedUserQueryNameRegex = new Regex(nameRegex, RegexOptions.IgnoreCase);
                }
                catch (ArgumentException ex)
                {
                    throw new AgErrorMessage(string.Format(MsgInvalidRegex, Param1InputUserQueryNameRegex, nameRegex, ex.Message));
                }
            }

            if (string.IsNullOrEmpty(includeTemplatedFilters))
            {
                includeTemplatedFilters = "NVI";
            }
            else
            {
                if (!Regex.IsMatch(includeTemplatedFilters, "^[nvi]+$", RegexOptions.IgnoreCase))
                {
                    throw new AgErrorMessage(string.Format(MsgInvalidNVI, Param5InputIncludeTemplatedFilters, includeTemplatedFilters));
                }
            }
            this.InterpretTemplatedFilters(includeTemplatedFilters);
        }

        private void InterpretTemplatedFilters(string includeTemplatedFilters)
        {
            this.IncludeNotTemplated = (includeTemplatedFilters.IndexOf("N", 0, StringComparison.CurrentCultureIgnoreCase) != -1);
            this.IncludeInvalidTemplated = (includeTemplatedFilters.IndexOf("I", 0, StringComparison.CurrentCultureIgnoreCase) != -1);
            this.IncludeValidTemplated = (includeTemplatedFilters.IndexOf("V", 0, StringComparison.CurrentCultureIgnoreCase) != -1);
        }

        private void RetrieveUserQueries(CodeActivityContext executionContext)
        {
            QueryExpression query = new QueryExpression
            {
                EntityName = AgViewsUtils.EntityNameUserQuery,
                ColumnSet = new ColumnSet(true)
            };

            Guid user = this.ValidatedUserQueryOwner.Id;
            IOrganizationService svc = this.GetService(executionContext, user);

            DataCollection<Entity> responses = svc.RetrieveMultiple(query).Entities;
            List<Entity> filteredViews = this.FilterViews(responses, executionContext);

            this.SetOutputValues(filteredViews, executionContext);
        }

        private void SetOutputValues(List<Entity> filteredViews, CodeActivityContext executionContext)
        {
            this.OutputViewCount.Set(executionContext, filteredViews.Count);
            this.OutputViewDefinitions.Set(executionContext, this.Serialize(filteredViews));
        }

        private List<Entity> FilterViews(DataCollection<Entity> views, CodeActivityContext executionContext)
        {
            List<Entity> filteredViews = new List<Entity>();
            foreach (Entity entity in views)
            {
                if (this.ValidatedUserQueryNameRegex.IsMatch((string)entity.Attributes[AgViewsUtils.FieldName]))
                {
                    if (this.ValidatedEntityLogicalNameRegex.IsMatch((string)entity.Attributes[AgViewsUtils.FieldReturnedTypeCode]))
                    {
                        if (this.ValidatedQueryTypes.Contains((int)entity.Attributes[AgViewsUtils.FieldQueryType]))
                        {
                            if (this.IncludeTemplated(entity, executionContext))
                            {
                                filteredViews.Add(entity);
                            }
                        }
                    }
                }
            }

            return filteredViews;
        }

        private bool IncludeTemplated(Entity entity, CodeActivityContext executionContext)
        {
            int queryType = (int)entity.Attributes[AgViewsUtils.FieldQueryType];

            if (queryType != UserQueryQueryType.OfflineFilters && queryType != UserQueryQueryType.OutlookFilters)
            {
                return true;
            }

            if (entity.Attributes.Contains(AgViewsUtils.FieldParentQueryId))
            {
                EntityReference parentReference = (EntityReference)entity.Attributes[AgViewsUtils.FieldParentQueryId];
                Guid templateId = parentReference.Id;
                if (this.TemplateExists(templateId, executionContext))
                {
                    if (this.IncludeValidTemplated)
                    {
                        return true;
                    }
                }
                else if (this.IncludeInvalidTemplated)
                {
                    return true;
                }
            }
            else if (this.IncludeNotTemplated)
            {
                return true;
            }

            return false;
        }

        private bool TemplateExists(Guid key, CodeActivityContext executionContext)
        {
            QueryExpression query = new QueryExpression
            {
                EntityName = AgViewsUtils.EntityNameSavedQuery,
                ColumnSet = new ColumnSet(),
                Criteria = new FilterExpression
                {
                    Conditions = 
                    {
                        new ConditionExpression
                        {
                            AttributeName = AgViewsUtils.FieldSavedQueryId,
                            Operator = ConditionOperator.Equal,
                            Values = { key }
                        }
                    }
                }
            };

            EntityCollection templates = this.GetService(executionContext).RetrieveMultiple(query);
            if (templates.Entities.Count == 0)
            {
                return false;
            }
            else
            {
                return true;
            }
        }

        #endregion

    }
    */
}
